package com.fly;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Collection;
import java.util.Scanner;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.eclipse.jetty.runner.Runner;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@SuppressWarnings("deprecation")
public class JettyExtraRunner
{
    private static URL url = JettyExtraRunner.class.getProtectionDomain().getCodeSource().getLocation();
    
    /**
     * 遍历文件或Jar寻找war运行
     * 
     * @param args
     * @throws IOException
     */
    public static void main(String[] args)
        throws IOException
    {
        log.info("类加载路径: {}", url.getPath());
        boolean isJar = url.getPath().endsWith(".jar");
        if (isJar)
        {
            processInJar(args);
        }
        else
        {
            processInDev();
        }
    }
    
    /**
     * Jar遍历-寻找war-拷贝-运行
     * 
     * @param args
     * @throws IOException
     */
    private static void processInJar(String[] args)
        throws IOException
    {
        // 调用方式1: java -jar jetty-runner-extra.jar 搜索jar内存在的war运行，否则给出提示 war不存在，程序终止
        if (args.length == 0)
        {
            try (JarInputStream jis = new JarInputStream(new FileInputStream(url.getFile())))
            {
                int num = 0;
                JarEntry jarEntry;
                while ((jarEntry = jis.getNextJarEntry()) != null)
                {
                    String name = jarEntry.getName();
                    if (name.endsWith(".war"))
                    {
                        num++;
                        log.info("即将加载运行：{}", name);
                        try (InputStream is = JettyExtraRunner.class.getResourceAsStream("/" + name))
                        {
                            File file = new File(name);
                            FileUtils.copyInputStreamToFile(is, file);
                            Runner.main(new String[] {file.getCanonicalPath()});
                            return;
                        }
                    }
                }
                if (num == 0)
                {
                    log.error("未发现war文件，程序终止");
                }
            }
            return;
        }
        
        // 调用方式2: java -jar jetty-runner-extra.jar --addwar 交互运行，列出当前目录(包含子目录)war供选择添加
        if (args.length == 1 && "--addwar".equals(args[0]))
        {
            Collection<File> files = FileUtils.listFiles(new File(url.getPath()).getParentFile(), new String[] {"war"}, true);
            if (files.isEmpty())
            {
                log.error("未发现war文件，无法添加");
                return;
            }
            File selected;
            if (files.size() == 1)
            {
                selected = files.toArray(new File[0])[0];
            }
            else
            {
                // 列出->选择
                try (Scanner sc = new Scanner(System.in))
                {
                    int input;
                    do
                    {
                        int index = 1;
                        for (File file : files)
                        {
                            log.info("序号{}: {}", index++, file.getCanonicalPath());
                        }
                        log.info("请输入序号1-{}选择war文件", files.size());
                        input = sc.nextInt();
                    } while (input < 1 || input > files.size());
                    selected = files.toArray(new File[0])[input - 1];
                    log.info("你选择了war文件：{} ", selected.getCanonicalPath());
                }
            }
            addWar(selected);
            return;
        }
        
        // 调用方式3: java -jar jetty-runner-extra.jar --addwar war/simple.war 如指定的war存在，直接添加，否则给出提示 war不存在，程序终止
        if (args.length == 2 && "--addwar".equals(args[0]))
        {
            String path = args[1];
            File war = new File(path);
            if (war.exists())
            {
                log.info("文件：{}", war.getCanonicalPath());
                addWar(war);
            }
            else
            {
                log.error("{} 不存在，程序终止", path);
            }
            return;
        }
    }
    
    /**
     * 添加war到新jar中
     * 
     * @param war
     * @see [类、类#方法、类#成员]
     */
    private static void addWar(File war)
    {
        try
        {
            File srcJar = new File(url.getPath());
            String newJar = srcJar.getCanonicalPath().replace(".jar", DateFormatUtils.format(System.currentTimeMillis(), "_HHmmssSSS") + ".jar");
            addWarToJar(war, srcJar, newJar);
        }
        catch (IOException e)
        {
            log.error(e.getMessage(), e);
        }
    }
    
    /**
     * 将war添加到srcJar并重命名为newJar
     * 
     * @param war
     * @param srcJar
     * @param newJar
     * @throws IOException
     */
    private static void addWarToJar(File war, File srcJar, String newJar)
        throws IOException
    {
        log.info("即将添加war文件:{} 到 {} 中...", war.getCanonicalPath(), newJar);
        try (JarInputStream jis = new JarInputStream(new FileInputStream(url.getFile())); JarOutputStream jos = new JarOutputStream(new FileOutputStream(newJar), jis.getManifest()))
        {
            JarEntry jarEntry;
            while ((jarEntry = jis.getNextJarEntry()) != null)
            {
                jos.putNextEntry(jarEntry);
                IOUtils.copy(jis, jos);
            }
            
            // 追加war写入数据
            JarEntry warEntry = new JarEntry("war/" + war.getName());
            jos.putNextEntry(warEntry);
            try (InputStream inputStream = new FileInputStream(war))
            {
                IOUtils.copy(inputStream, jos);
            }
        }
    }
    
    /**
     * 开发模式下，file遍历-寻找war-运行
     * 
     * @throws IOException
     */
    private static void processInDev()
        throws IOException
    {
        Collection<File> files = FileUtils.listFiles(new File(url.getPath()), new String[] {"war"}, true);
        if (files.isEmpty())
        {
            log.error("未发现war文件，程序终止");
            return;
        }
        if (files.size() > 1)
        {
            log.error("存在多个war文件，请移除多余war，保留1个");
            return;
        }
        // 加载运行唯一war
        for (File file : files)
        {
            log.info("加载运行：{}", file.getCanonicalPath());
            Runner.main(new String[] {file.getCanonicalPath()});
            return;
        }
    }
}
